//
// Created by Administrator on 2025/9/16.
//

#include "norflash.h"
extern DMA_HandleTypeDef hdma_spi1_rx;
extern DMA_HandleTypeDef hdma_spi1_tx;
void NORFLASH_SPI_DMA_TX_CPLT_CB(DMA_HandleTypeDef *_hdma);
static volatile bool g_spi_dma_tx_flag=false;

void norflash_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_initstruct.Pin = NORFLASH_CS_PIN;
    gpio_initstruct.Pull=GPIO_PULLUP;
    HAL_GPIO_Init(NORFLASH_CS_GPIO_PORT, &gpio_initstruct);
    NORFLASH_CS_OUT(1);
    norflash_set_speed(SPI_BAUDRATEPRESCALER_4);
    // __HAL_DMA_ENABLE_IT(&hdma_spi1_tx,DMA_IT_TC);
    // HAL_DMA_RegisterCallback(&hdma_spi1_tx,HAL_DMA_XFER_CPLT_CB_ID,NORFLASH_SPI_DMA_TX_CPLT_CB);
    // __HAL_DMA_ENABLE_IT(&hdma_spi1_rx,DMA_IT_TC);
    // HAL_DMA_RegisterCallback(&hdma_spi1_rx,HAL_DMA_XFER_CPLT_CB_ID,NORFLASH_SPI_DMA_TX_CPLT_CB);
}

uint8_t norflash_wr_byte(uint8_t txdata)
{
    uint8_t rxdata=0;
    HAL_SPI_TransmitReceive_DMA(&hspi1,&txdata,&rxdata,1);
    bool sta = false;
    sta=get_norflash_tx_cplt_flag();
    while (!sta);
    return rxdata;
}
uint16_t norflash_getID(void)
{
    uint16_t id=0;
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_ManufactDeviceID);
    norflash_wr_byte(0);
    norflash_wr_byte(0);
    norflash_wr_byte(0);
    id=norflash_wr_byte(0xff);
    id<<=8;
    id|=norflash_wr_byte(0xff);
    NORFLASH_CS_OUT(1);
    return id;
}

void norflash_set_speed(uint32_t speed)
{
    speed=(speed+7)/8;
    __HAL_SPI_DISABLE(&hspi1);
    hspi1.Instance->CR1&=0xffc7;
    hspi1.Instance->CR1|=speed;
    __HAL_SPI_ENABLE(&hspi1);
}
void norflash_write_enable(void)
{
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_WriteEnable);
    NORFLASH_CS_OUT(1);
}

void norflash_write_disable(void)
{
    norflash_wr_byte(FLASH_WriteDisable);
}
void norflash_wait_ready(void)
{
    while(norflash_read_status()&0x01);
}
uint8_t norflash_read_status(void)
{
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_ReadStatusReg1);
    uint8_t status=norflash_wr_byte(0xff);
    NORFLASH_CS_OUT(1);
    return status;
}
void norflash_write_status(uint8_t status)
{

}
void norflash_sector_erase(uint32_t addr)
{
    norflash_write_enable();
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_SectorErase);
    norflash_wr_byte((uint8_t)(addr>>16));
    norflash_wr_byte((uint8_t)(addr>>8));
    norflash_wr_byte((uint8_t)(addr));
    NORFLASH_CS_OUT(1);
    norflash_wait_ready();
}


void norflash_page_write(uint32_t addr,uint8_t *buf,uint16_t len)
{
    norflash_wait_ready();
    norflash_write_enable();
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_PageProgram);
    norflash_wr_byte((uint8_t)(addr>>16));
    norflash_wr_byte((uint8_t)(addr>>8));
    norflash_wr_byte((uint8_t)(addr));
    for(uint16_t i=0;i<len;i++)
    {
        norflash_wr_byte(buf[i]);
    }
    //norflash_write_disable();
    NORFLASH_CS_OUT(1);
    norflash_wait_ready();
}




// void norflash_write_api(uint32_t addr,uint8_t *buf,uint16_t len)
// {
//     uint32_t space = 256-addr % 256;
//     if(len <= space)
//         space=len;
//     while (1)
//     {
//         norflash_page_write(addr,buf,space);
//         buf+=space;
//         addr+=space;
//         len-=space;
//         space=256;
//         if (len  <= space)
//         {
//             norflash_page_write(addr,buf,len);
//             return;
//         }
//     }
// }
void norflash_write_api(uint32_t addr, uint8_t *buf, uint16_t len)
{
    uint16_t bytes_to_write_this_page;

    // 只要还有数据没写完，就继续循环
    while (len > 0)
    {
        // 1. 计算在当前页还剩下多少空间
        uint16_t page_remain = 256 - (addr % 256);

        // 2. 确定本次写入的长度：取“剩余页空间”和“剩余数据长度”中的较小者
        bytes_to_write_this_page = (len < page_remain) ? len : page_remain;

        // 3. 调用底层的页写入函数
        norflash_page_write(addr, buf, bytes_to_write_this_page);

        // 4. 更新地址、缓冲区指针和剩余长度，为下一次循环做准备
        addr += bytes_to_write_this_page;
        buf  += bytes_to_write_this_page;
        len  -= bytes_to_write_this_page;
    }
}
void norflash_write(uint32_t addr, uint8_t *buf, uint16_t len)
{
    // 扇区大小为4KB (0x1000)
    static uint8_t sector_buf[4096]; // 使用静态变量以避免栈溢出
    uint32_t sector_addr;
    uint16_t offset_in_sector;
    uint16_t bytes_to_write_this_sector;
    // 只要还有数据没写完，就继续循环
    while (len > 0)
    {
        // 1. 计算当前地址所在的扇区基地址
        sector_addr = addr & 0xFFFFF000; // 等效于 (addr / 4096) * 4096

        // 2. 计算要写入的数据在扇区内的偏移
        offset_in_sector = addr & 0xFFF; // 等效于 addr % 4096

        // 3. 计算本次循环需要在这个扇区内写入多少字节
        //    取“本扇区剩余空间”和“数据剩余总长度”中的较小者
        uint16_t sector_remain = 4096 - offset_in_sector;
        bytes_to_write_this_sector = (len < sector_remain) ? len : sector_remain;

        // --- 开始“读-改-擦-写”的标准流程 ---

        // 步骤 A: 【备份】读取整个扇区的数据到RAM缓冲区
        norflash_read(sector_addr, sector_buf, 4096);

        // 步骤 B: 【合并】将用户传入的新数据，覆盖到RAM缓冲区中对应位置
        // 使用 memcpy 效率更高
        memcpy(sector_buf + offset_in_sector, buf, bytes_to_write_this_sector);

        // 步骤 C: 【擦除】擦除整个扇区
        norflash_sector_erase(sector_addr);

        // 步骤 D: 【写回】将修改后的整个4KB缓冲区数据，全部写回Flash
        // 这里要使用我们修正过的、支持跨页的 norflash_write_api
        norflash_write_api(sector_addr, sector_buf, 4096);

        // --- 流程结束 ---

        // 4. 更新地址、缓冲区指针和剩余长度，为处理下一个扇区做准备
        addr += bytes_to_write_this_sector;
        buf  += bytes_to_write_this_sector;
        len  -= bytes_to_write_this_sector;
    }
}
// void norflash_write(uint32_t addr,uint8_t *buf,uint16_t len)
// {
//     uint8_t sector_buf[4096]={0};
//     uint16_t sector=addr/4096;
//     uint16_t rw_pos=addr%4096;
//     uint16_t space= 4096-rw_pos;
//     uint16_t temp_len=len;
//     if(space<=temp_len)
//         space=temp_len;
//     while(1)
//     {
//         norflash_read(sector*4096,sector_buf,4096);
//         norflash_sector_erase(sector*4096);
//         norflash_write_api(sector*4096,sector_buf,rw_pos);
//         if (temp_len<=space)
//         {
//             norflash_write_api(sector*4096+rw_pos+temp_len,sector_buf+rw_pos+temp_len,4096-rw_pos-temp_len);
//             break;
//         }
//         else
//         {
//             sector++;
//             rw_pos=0;
//             temp_len-=space;
//             space=4096;
//         }
//     }
//     norflash_write_api(addr,buf,len);
// }
void norflash_read(uint32_t addr,uint8_t *buf,uint16_t len)
{
    norflash_wait_ready();
    NORFLASH_CS_OUT(0);
    norflash_wr_byte(FLASH_ReadData);
    norflash_wr_byte((uint8_t)(addr>>16));
    norflash_wr_byte((uint8_t)(addr>>8));
    norflash_wr_byte((uint8_t)(addr));
    while (len--)
    {
        *buf++=norflash_wr_byte(0xff);
    }
    NORFLASH_CS_OUT(1);

}

// void NORFLASH_SPI_DMA_TX_CPLT_CB(DMA_HandleTypeDef *_hdma)
// {
//     UNUSED(_hdma);
//     g_spi_dma_tx_flag=true;
// }

volatile bool get_norflash_tx_cplt_flag(void)
{
    bool tmp=g_spi_dma_tx_flag;
    g_spi_dma_tx_flag=false;
    return tmp;
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance==SPI1)
    {
        g_spi_dma_tx_flag=true;
    }
}
// 定义用于测试的Flash地址和数据长度
#define TEST_ADDR   0x10000  // 选择一个安全的测试地址，例如1M字节处
#define TEST_SIZE   512      // 测试数据长度，选择一个大于256的值可以测试跨页写入

/**
 * @brief  NOR Flash 全面测试函数
 * @retval 0: 测试成功
 * @retval 非0: 测试失败 (返回值对应失败的步骤)
 */
uint8_t norflash_test_run(void)
{
    uint16_t id;
    uint8_t tx_buffer[TEST_SIZE];
    uint8_t rx_buffer[TEST_SIZE];
    uint16_t i;

    printf("--- NOR Flash Test Start ---\r\n");

    // --- 步骤 1: 读取 JEDEC ID ---
    id = norflash_getID();
    printf("[Step 1] Read JEDEC ID...\r\n");
    if (id == 0xFFFF || id == 0x0000)
    {
        printf("  [Error] Failed to get device ID! Check SPI connection. Got: 0x%04X\r\n", id);
        return 1;
    }
    else
    {
        // 例如，W25Q128的ID是 0xEF17
        printf("  [OK] Device ID: 0x%04X\r\n", id);
    }

    // --- 步骤 2: 准备测试数据 ---
    printf("[Step 2] Preparing test data (%d bytes)...\r\n", TEST_SIZE);
    for (i = 0; i < TEST_SIZE; i++)
    {
        tx_buffer[i] = i % 256; // 使用 0-255 的循环数据填充
    }
    memset(rx_buffer, 0, TEST_SIZE); // 清空接收缓冲区
    printf("  [OK] Test data prepared.\r\n");


    // --- 步骤 3: 擦除扇区 ---
    // norflash_write 函数内部会自动处理擦除，但为了独立测试擦除功能，我们在这里手动执行。
    // 由于我们的测试数据长度为512字节，它肯定在一个4KB的扇区内。
    printf("[Step 3] Erasing sector at address 0x%08X...\r\n", (unsigned int)TEST_ADDR);
    norflash_sector_erase(TEST_ADDR);
    printf("  [OK] Erase command sent.\r\n");


    // --- 步骤 4: 验证擦除 ---
    printf("[Step 4] Verifying erase...\r\n");
    norflash_read(TEST_ADDR, rx_buffer, TEST_SIZE);
    for(i = 0; i < TEST_SIZE; i++)
    {
        if(rx_buffer[i] != 0xFF)
        {
            printf("  [Error] Erase verification failed at address 0x%08X!\r\n", (unsigned int)(TEST_ADDR + i));
            printf("  Expected: 0xFF, Got: 0x%02X\r\n", rx_buffer[i]);
            return 4;
        }
    }
    printf("  [OK] Sector erased successfully.\r\n");


    // --- 步骤 5: 写入数据 ---
    printf("[Step 5] Writing %d bytes to address 0x%08X...\r\n", TEST_SIZE, (unsigned int)TEST_ADDR);
    // 这里我们直接调用最高层的 norflash_write 函数，因为它会测试到其下层的 norflash_write_api 等函数
    norflash_write(TEST_ADDR, tx_buffer, TEST_SIZE);
    printf("  [OK] Write finished.\r\n");


    // --- 步骤 6: 回读数据 ---
    printf("[Step 6] Reading back %d bytes from address 0x%08X...\r\n", TEST_SIZE, (unsigned int)TEST_ADDR);
    norflash_read(TEST_ADDR, rx_buffer, TEST_SIZE);
    printf("  [OK] Read finished.\r\n");


    // --- 步骤 7: 校验数据 ---
    printf("[Step 7] Verifying data...\r\n");
    if (memcmp(tx_buffer, rx_buffer, TEST_SIZE) == 0)
    {
        printf("  [OK] Data verification successful!\r\n");
    }
    else
    {
        printf("  [Error] Data verification failed!\r\n");
        // 找出第一个不匹配的字节，方便调试
        for (i = 0; i < TEST_SIZE; i++)
        {
            if (tx_buffer[i] != rx_buffer[i])
            {
                printf("  Mismatch at offset %d (Address 0x%08X): Expected 0x%02X, Got 0x%02X\r\n",
                       i, (unsigned int)(TEST_ADDR + i), tx_buffer[i], rx_buffer[i]);
                break; // 只打印第一个错误
            }
        }
        return 7;
    }

    printf("--- NOR Flash Test PASSED! ---\r\n\r\n");
    return 0; // 所有测试通过
}

